Obvladajte testiranje React komponent z React Testing Library. Spoznajte najboljše prakse za pisanje vzdržljivih in učinkovitih testov, osredotočenih na vedenje uporabnikov in dostopnost.
React Testing Library: Najboljše prakse testiranja komponent za globalne ekipe
V nenehno razvijajočem se svetu spletnega razvoja je zagotavljanje zanesljivosti in kakovosti vaših React aplikacij ključnega pomena. To še posebej velja za globalne ekipe, ki delajo na projektih z raznolikimi uporabniškimi bazami in zahtevami po dostopnosti. React Testing Library (RTL) ponuja zmogljiv in na uporabnika osredotočen pristop k testiranju komponent. Za razliko od tradicionalnih metod testiranja, ki se osredotočajo na podrobnosti implementacije, vas RTL spodbuja, da testirate svoje komponente tako, kot bi z njimi komuniciral uporabnik, kar vodi do bolj robustnih in vzdržljivih testov. Ta celovit vodnik se bo poglobil v najboljše prakse za uporabo RTL v vaših React projektih, s poudarkom na gradnji aplikacij, primernih za globalno občinstvo.
Zakaj React Testing Library?
Preden se poglobimo v najboljše prakse, je ključnega pomena razumeti, zakaj RTL izstopa od drugih knjižnic za testiranje. Tu je nekaj ključnih prednosti:
- Na uporabnika osredotočen pristop: RTL daje prednost testiranju komponent z vidika uporabnika. S komponento komunicirate z istimi metodami, kot bi jih uporabil uporabnik (npr. klikanje gumbov, vnašanje v polja), kar zagotavlja bolj realistično in zanesljivo izkušnjo testiranja.
- Osredotočenost na dostopnost: RTL spodbuja pisanje dostopnih komponent, saj vas spodbuja k testiranju na način, ki upošteva uporabnike z oviranostmi. To je v skladu z globalnimi standardi dostopnosti, kot je WCAG.
- Manj vzdrževanja: S tem, ko se izogibate testiranju podrobnosti implementacije (npr. notranjega stanja, specifičnih klicev funkcij), je manj verjetno, da se bodo testi RTL zlomili, ko boste preoblikovali svojo kodo. To vodi do bolj vzdržljivih in odpornih testov.
- Izboljšan dizajn kode: Na uporabnika osredotočen pristop RTL pogosto vodi do boljšega oblikovanja komponent, saj ste prisiljeni razmišljati o tem, kako bodo uporabniki komunicirali z vašimi komponentami.
- Skupnost in ekosistem: RTL se ponaša z veliko in aktivno skupnostjo, ki zagotavlja obilo virov, podpore in razširitev.
Nastavitev testnega okolja
Za začetek dela z RTL boste morali nastaviti svoje testno okolje. Tu je osnovna nastavitev z uporabo Create React App (CRA), ki ima že prednameščena Jest in RTL:
npx create-react-app my-react-app
cd my-react-app
npm install --save-dev @testing-library/react @testing-library/jest-dom
Pojasnilo:
- `npx create-react-app my-react-app`: Ustvari nov React projekt z uporabo Create React App.
- `cd my-react-app`: Premakne vas v novo ustvarjeno mapo projekta.
- `npm install --save-dev @testing-library/react @testing-library/jest-dom`: Namesti potrebne RTL pakete kot razvojne odvisnosti. `@testing-library/react` zagotavlja osnovno funkcionalnost RTL, medtem ko `@testing-library/jest-dom` zagotavlja uporabne Jest "matcherje" za delo z DOM.
Če ne uporabljate CRA, boste morali namestiti Jest in RTL ločeno ter nastaviti Jest za uporabo RTL.
Najboljše prakse za testiranje komponent z React Testing Library
1. Pišite teste, ki posnemajo interakcije uporabnikov
Osnovno načelo RTL je testiranje komponent tako, kot bi jih uporabljal uporabnik. To pomeni osredotočanje na to, kar uporabnik vidi in počne, namesto na notranje podrobnosti implementacije. Uporabite objekt `screen`, ki ga ponuja RTL, za poizvedovanje po elementih na podlagi njihovega besedila, vloge ali oznak za dostopnost.
Primer: Testiranje klika na gumb
Recimo, da imate preprosto komponento gumba:
// Button.js
import React from 'react';
function Button({ onClick, children }) {
return ;
}
export default Button;
Tukaj je primer, kako jo testirati z uporabo RTL:
// Button.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
describe('Button Component', () => {
it('calls the onClick handler when clicked', () => {
const handleClick = jest.fn();
render();
const buttonElement = screen.getByText('Click Me');
fireEvent.click(buttonElement);
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
Pojasnilo:
- `render()`: Izriše komponento Button z lažnim (mock) `onClick` obravnavalcem.
- `screen.getByText('Click Me')`: Poizveduje po dokumentu za elementom, ki vsebuje besedilo "Click Me". Tako bi uporabnik identificiral gumb.
- `fireEvent.click(buttonElement)`: Simulira dogodek klika na element gumba.
- `expect(handleClick).toHaveBeenCalledTimes(1)`: Preveri, ali je bil `onClick` obravnavalec poklican enkrat.
Zakaj je to boljše od testiranja podrobnosti implementacije: Predstavljajte si, da preoblikujete komponento Button, da uporablja drug obravnavalec dogodkov ali spremeni notranje stanje. Če bi testirali specifično funkcijo obravnavalca dogodkov, bi se vaš test zlomil. Z osredotočanjem na interakcijo uporabnika (klikanje gumba) test ostane veljaven tudi po preoblikovanju.
2. Dajte prednost poizvedbam, ki temeljijo na nameri uporabnika
RTL ponuja različne metode poizvedovanja za iskanje elementov. Dajte prednost naslednjim poizvedbam v tem vrstnem redu, saj najbolje odražajo, kako uporabniki dojemajo in komunicirajo z vašimi komponentami:
- getByRole: Ta poizvedba je najbolj dostopna in bi morala biti vaša prva izbira. Omogoča vam iskanje elementov na podlagi njihovih ARIA vlog (npr. gumb, povezava, naslov).
- getByLabelText: Uporabite to za iskanje elementov, povezanih z določeno oznako (label), kot so vnosna polja.
- getByPlaceholderText: Uporabite to za iskanje vnosnih polj na podlagi njihovega nadomestnega besedila (placeholder).
- getByText: Uporabite to za iskanje elementov na podlagi njihovega besedilne vsebine. Bodite specifični in se izogibajte uporabi splošnega besedila, ki se lahko pojavi na več mestih.
- getByDisplayValue: Uporabite to za iskanje vnosnih polj na podlagi njihove trenutne vrednosti.
Primer: Testiranje vnosnega polja v obrazcu
// Input.js
import React from 'react';
function Input({ label, placeholder, value, onChange }) {
return (
);
}
export default Input;
Tukaj je primer, kako ga testirati z uporabo priporočenega vrstnega reda poizvedb:
// Input.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Input from './Input';
describe('Input Component', () => {
it('updates the value when the user types', () => {
const handleChange = jest.fn();
render();
const inputElement = screen.getByLabelText('Name');
fireEvent.change(inputElement, { target: { value: 'John Doe' } });
expect(handleChange).toHaveBeenCalledTimes(1);
expect(handleChange).toHaveBeenCalledWith(expect.objectContaining({ target: { value: 'John Doe' } }));
});
});
Pojasnilo:
- `screen.getByLabelText('Name')`: Uporabi `getByLabelText` za iskanje vnosnega polja, povezanega z oznako "Name". To je najbolj dostopen in uporabniku prijazen način za lociranje vnosnega polja.
3. Izogibajte se testiranju podrobnosti implementacije
Kot smo že omenili, se izogibajte testiranju notranjega stanja, klicev funkcij ali specifičnih CSS razredov. To so podrobnosti implementacije, ki se lahko spremenijo in vodijo do krhkih testov. Osredotočite se na opazno vedenje komponente.
Primer: Izogibajte se neposrednemu testiranju stanja
Namesto da testirate, ali je določena spremenljivka stanja posodobljena, testirajte, ali komponenta izriše pravilen izhod na podlagi tega stanja. Na primer, če komponenta prikaže sporočilo na podlagi logične spremenljivke stanja, testirajte, ali je sporočilo prikazano ali skrito, namesto da testirate samo spremenljivko stanja.
4. Uporabite `data-testid` za specifične primere
Čeprav je na splošno najbolje, da se izogibate uporabi atributov `data-testid`, obstajajo specifični primeri, kjer so lahko koristni:
- Elementi brez semantičnega pomena: Če morate ciljati na element, ki nima pomembne vloge, oznake ali besedila, lahko uporabite `data-testid`.
- Kompleksne strukture komponent: V kompleksnih strukturah komponent vam lahko `data-testid` pomaga ciljati na specifične elemente, ne da bi se zanašali na krhke selektorje.
- Testiranje dostopnosti: `data-testid` se lahko uporablja za identifikacijo specifičnih elementov med testiranjem dostopnosti z orodji, kot sta Cypress ali Playwright.
Primer: Uporaba `data-testid`
// MyComponent.js
import React from 'react';
function MyComponent() {
return (
This is my component.
);
}
export default MyComponent;
// MyComponent.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders the component container', () => {
render( );
const containerElement = screen.getByTestId('my-component-container');
expect(containerElement).toBeInTheDocument();
});
});
Pomembno: Uporabljajte `data-testid` zmerno in samo takrat, ko druge metode poizvedovanja niso primerne.
5. Pišite smiselne opise testov
Jasni in jedrnati opisi testov so ključnega pomena za razumevanje namena vsakega testa in za odpravljanje napak. Uporabljajte opisna imena, ki jasno pojasnjujejo, kaj test preverja.
Primer: Dobri in slabi opisi testov
Slabo: `it('deluje')`
Dobro: `it('prikaže pravilno pozdravno sporočilo')`
Še bolje: `it('prikaže pozdravno sporočilo "Hello, World!", ko prop "name" ni podan')`
Boljši primer jasno navaja pričakovano vedenje komponente pod določenimi pogoji.
6. Ohranjajte teste majhne in osredotočene
Vsak test bi se moral osredotočiti na preverjanje enega samega vidika delovanja komponente. Izogibajte se pisanju velikih, kompleksnih testov, ki pokrivajo več scenarijev. Majhni, osredotočeni testi so lažji za razumevanje, vzdrževanje in odpravljanje napak.
7. Uporabljajte testne dvojnike (mocks in spies) na ustrezen način
Testni dvojniki so koristni za izolacijo komponente, ki jo testirate, od njenih odvisnosti. Uporabljajte lažne objekte (mocks) in vohune (spies) za simulacijo zunanjih storitev, klicev API-ja ali drugih komponent.
Primer: Simulacija klica API-ja
// UserList.js
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
async function fetchUsers() {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
}
fetchUsers();
}, []);
return (
{users.map(user => (
- {user.name}
))}
);
}
export default UserList;
// UserList.test.js
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import UserList from './UserList';
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve([
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' },
]),
})
);
describe('UserList Component', () => {
it('fetches and displays a list of users', async () => {
render( );
// Wait for the data to load
await waitFor(() => screen.getByText('John Doe'));
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('Jane Smith')).toBeInTheDocument();
});
});
Pojasnilo:
- `global.fetch = jest.fn(...)`: Ustvari lažno funkcijo (mock) `fetch`, da vrne vnaprej določen seznam uporabnikov. To vam omogoča testiranje komponente brez odvisnosti od prave končne točke API-ja.
- `await waitFor(() => screen.getByText('John Doe'))`: Počaka, da se v dokumentu pojavi besedilo "John Doe". To je potrebno, ker se podatki pridobivajo asinhrono.
8. Testirajte robne primere in obravnavo napak
Ne testirajte samo srečne poti. Poskrbite, da boste testirali tudi robne primere, scenarije napak in mejne pogoje. To vam bo pomagalo zgodaj odkriti morebitne težave in zagotoviti, da vaša komponenta elegantno obravnava nepričakovane situacije.
Primer: Testiranje obravnave napak
Predstavljajte si komponento, ki pridobiva podatke iz API-ja in prikaže sporočilo o napaki, če klic API-ja ne uspe. Napisati bi morali test, ki preveri, ali je sporočilo o napaki pravilno prikazano, ko klic API-ja ne uspe.
9. Osredotočite se na dostopnost
Dostopnost je ključnega pomena za ustvarjanje vključujočih spletnih aplikacij. Uporabite RTL za testiranje dostopnosti vaših komponent in zagotovite, da izpolnjujejo standarde dostopnosti, kot je WCAG. Nekateri ključni vidiki dostopnosti vključujejo:
- Semantični HTML: Uporabljajte semantične elemente HTML (npr. `
- Atributi ARIA: Uporabljajte atribute ARIA za zagotavljanje dodatnih informacij o vlogi, stanju in lastnostih elementov, zlasti za komponente po meri.
- Navigacija s tipkovnico: Zagotovite, da so vsi interaktivni elementi dostopni preko navigacije s tipkovnico.
- Barvni kontrast: Uporabljajte zadosten barvni kontrast, da zagotovite berljivost besedila za uporabnike s slabšim vidom.
- Združljivost z bralniki zaslona: Testirajte svoje komponente z bralnikom zaslona, da zagotovite smiselno in razumljivo izkušnjo za uporabnike z okvarami vida.
Primer: Testiranje dostopnosti z `getByRole`
// MyAccessibleComponent.js
import React from 'react';
function MyAccessibleComponent() {
return (
);
}
export default MyAccessibleComponent;
// MyAccessibleComponent.test.js
import React from 'react';
import { render, screen } from '@testing-library/react';
import MyAccessibleComponent from './MyAccessibleComponent';
describe('MyAccessibleComponent', () => {
it('renders an accessible button with the correct aria-label', () => {
render( );
const buttonElement = screen.getByRole('button', { name: 'Close' });
expect(buttonElement).toBeInTheDocument();
});
});
Pojasnilo:
- `screen.getByRole('button', { name: 'Close' })`: Uporabi `getByRole` za iskanje elementa gumba z dostopnim imenom "Close". To zagotavlja, da je gumb pravilno označen za bralnike zaslona.
10. Vključite testiranje v svoj razvojni proces
Testiranje bi moralo biti sestavni del vašega razvojnega procesa, ne pa nekaj, o čemer razmišljate naknadno. Vključite svoje teste v svoj CI/CD cevovod, da se testi samodejno izvajajo ob vsaki oddaji ali uvedbi kode. To vam bo pomagalo zgodaj odkriti napake in preprečiti regresije.
11. Upoštevajte lokalizacijo in internacionalizacijo (i18n)
Pri globalnih aplikacijah je ključnega pomena, da med testiranjem upoštevate lokalizacijo in internacionalizacijo (i18n). Zagotovite, da se vaše komponente pravilno izrisujejo v različnih jezikih in lokalih.
Primer: Testiranje lokalizacije
Če uporabljate knjižnico, kot je `react-intl` ali `i18next`, za lokalizacijo, lahko v svojih testih simulirate kontekst lokalizacije, da preverite, ali vaše komponente prikazujejo pravilno prevedeno besedilo.
12. Uporabite funkcije za izris po meri za ponovno uporabljivo nastavitev
Pri delu na večjih projektih se vam lahko zgodi, da ponavljate iste korake nastavitve v več testih. Da bi se izognili podvajanju, ustvarite funkcije za izris po meri, ki združujejo skupno logiko nastavitve.
Primer: Funkcija za izris po meri
// test-utils.js
import React from 'react';
import { render } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import theme from './theme';
const AllTheProviders = ({ children }) => {
return (
{children}
);
}
const customRender = (ui, options) =>
render(ui, { wrapper: AllTheProviders, ...options })
// ponovno izvozi vse
export * from '@testing-library/react'
// prepiši metodo render
export { customRender as render }
// MyComponent.test.js
import React from 'react';
import { render, screen } from './test-utils'; // Uvozi render po meri
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders correctly with the theme', () => {
render( );
// Vaša testna logika tukaj
});
});
Ta primer ustvari funkcijo za izris po meri, ki komponento ovije s ThemeProvider. To vam omogoča enostavno testiranje komponent, ki so odvisne od teme, ne da bi morali v vsakem testu ponavljati nastavitev ThemeProvider.
Zaključek
React Testing Library ponuja zmogljiv in na uporabnika osredotočen pristop k testiranju komponent. Z upoštevanjem teh najboljših praks lahko pišete vzdržljive in učinkovite teste, ki se osredotočajo na vedenje uporabnikov in dostopnost. To bo vodilo do bolj robustnih, zanesljivih in vključujočih React aplikacij za globalno občinstvo. Ne pozabite dati prednosti interakcijam uporabnikov, izogibajte se testiranju podrobnosti implementacije, osredotočite se na dostopnost in vključite testiranje v svoj razvojni proces. S sprejetjem teh načel lahko zgradite visokokakovostne React aplikacije, ki ustrezajo potrebam uporabnikov po vsem svetu.
Ključni poudarki:
- Osredotočite se na interakcije uporabnikov: Testirajte komponente tako, kot bi z njimi komuniciral uporabnik.
- Dajte prednost dostopnosti: Zagotovite, da so vaše komponente dostopne uporabnikom z oviranostmi.
- Izogibajte se podrobnostim implementacije: Ne testirajte notranjega stanja ali klicev funkcij.
- Pišite jasne in jedrnate teste: Poskrbite, da bodo vaši testi enostavni za razumevanje in vzdrževanje.
- Vključite testiranje v svoj delovni proces: Avtomatizirajte svoje teste in jih redno izvajajte.
- Upoštevajte globalno občinstvo: Zagotovite, da vaše komponente dobro delujejo v različnih jezikih in lokalih.